#include "State.h"

StateElementFuncPtr StateElementFuncBase::create(RTMEUS::StateType type)
{
    if (type == RTMEUS::CHARSEQ_TYPE || type == RTMEUS::CHAR_TYPE)
        return StateElementFuncPtr(new StateElementFunc<unsigned char>("i"));
    if (type == RTMEUS::SHORTSEQ_TYPE || type == RTMEUS::SHORT_TYPE)
        return StateElementFuncPtr(new StateElementFunc<short>("i"));
    if (type == RTMEUS::LONGSEQ_TYPE || type == RTMEUS::LONG_TYPE)
        return StateElementFuncPtr(new StateElementFunc<long>("i"));
    if (type == RTMEUS::FLOATSEQ_TYPE || type == RTMEUS::FLOAT_TYPE)
        return StateElementFuncPtr(new StateElementFunc<float>("f"));
    if (type == RTMEUS::DOUBLESEQ_TYPE || type == RTMEUS::DOUBLE_TYPE)
        return StateElementFuncPtr(new StateElementFunc<double>("f"));
    throw EInvalidStateType("");
}

StateFactoryPtr StateBase::getStateFactory(RTMEUS::StateType type)
{
    StateFactoryPtr f;

    if      (type == RTMEUS::CHARSEQ_TYPE)   f = StateFactoryPtr(new SeqStateFactory<CORBA::CharSeq>());
    else if (type == RTMEUS::SHORTSEQ_TYPE)  f = StateFactoryPtr(new SeqStateFactory<CORBA::ShortSeq>());
    else if (type == RTMEUS::LONGSEQ_TYPE)   f = StateFactoryPtr(new SeqStateFactory<CORBA::LongSeq>());
    else if (type == RTMEUS::FLOATSEQ_TYPE)  f = StateFactoryPtr(new SeqStateFactory<CORBA::FloatSeq>());
    else if (type == RTMEUS::DOUBLESEQ_TYPE) f = StateFactoryPtr(new SeqStateFactory<CORBA::DoubleSeq>());
    else throw EInvalidStateType("?");

    return f;
}

RTMEUS::StateType StateBase::getStateType(const std::string &name)
{
  std::string n(name);
  std::transform(n.begin(), n.end(), n.begin(), (int (*)(int))std::toupper);

  if (n == "CHAR")   return RTMEUS::CHAR_TYPE;
  if (n == "SHORT")  return RTMEUS::SHORT_TYPE;
  if (n == "LONG")   return RTMEUS::LONG_TYPE;
  if (n == "FLOAT")  return RTMEUS::FLOAT_TYPE;
  if (n == "DOUBLE") return RTMEUS::DOUBLE_TYPE;
  if (n == "CHARSEQ")   return RTMEUS::CHARSEQ_TYPE;
  if (n == "SHORTSEQ")  return RTMEUS::SHORTSEQ_TYPE;
  if (n == "LONGSEQ")   return RTMEUS::LONGSEQ_TYPE;
  if (n == "FLOATSEQ")  return RTMEUS::FLOATSEQ_TYPE;
  if (n == "DOUBLESEQ") return RTMEUS::DOUBLESEQ_TYPE;
  throw EInvalidStateType(name);
}

StateBase::StateBase(coil::Properties &prop)
{
    unsigned short index=0;
    unsigned int length = 0;    
    coil::Properties def_val;

    if(prop.findNode("default")!=0)
        def_val << prop.getNode("default");
    
    // 個々のデータの設定
    if (prop.findNode("data")!=0) {
        coil::Properties data;
        data << prop.getNode("data");
        
        std::vector<coil::Properties*> leaf = data.getLeaf();
        m_profile.data_profiles.length(leaf.size());
        m_dataProperties.resize(leaf.size());
        std::vector<coil::Properties*>::iterator it;
        int i;
        for(it = leaf.begin(),i=0 ; it != leaf.end(); it++,i++) {
            coil::Properties p = **it, def = def_val;
            def << p; // defaultにマージ
            RTMEUS::DataProfile dprof;
            dprof.unique_name    = CORBA::string_dup((*it)->getName());
            dprof.index = index;
            std::string def_valstr = p.getValue();
            std::stringstream ss;
            ss << 0;
            if (def_valstr != "") dprof.default_value = CORBA::string_dup(def_valstr.c_str());
            else if(def_val["value"] != "") dprof.default_value = CORBA::string_dup(def_val["value"].c_str());
            else dprof.default_value = ss.str().c_str();

            m_profile.data_profiles[i] = dprof;
            m_dataProperties[i] = def; //unique_name以外は, ここにとっておく
            //
            index++;
        }
        length = leaf.size();
    }

    // データの総量のみを指定する方法
    if (prop.findNode("alldata")!=0){
        coil::Properties alldata;
        alldata << prop.getNode("alldata");
        
        int datanum = atoi(alldata["datanum"].c_str());
        coil::Properties def = def_val;

        m_profile.data_profiles.length(datanum);
        m_dataProperties.resize(datanum);

        for(int i=0 ; i < datanum; i++) {
            RTMEUS::DataProfile dprof;
            std::stringstream uname_ss;
            uname_ss << std::string("data") << i;
            dprof.unique_name    = CORBA::string_dup(uname_ss.str().c_str());
            dprof.index = index;
            dprof.default_value = CORBA::string_dup(def_val["value"].c_str());
            m_profile.data_profiles[i] = dprof;
            //
            m_dataProperties[i] = def; //unique_name以外は, ここにとっておく
            index++;
        }
        
        length = (unsigned int) datanum;
    }
    
    if ((int)length < atoi(prop["length"].c_str())) length = atoi(prop["length"].c_str());
    m_profile.length = length;
    // 最後にセット
    m_profile.name =  CORBA::string_dup(prop.getName());
}

void operator <<= (CORBA::Any &any, const StatePtr &state)
{
  state->setAny(any);
}
CORBA::Boolean operator >>= (const CORBA::Any &any, StatePtr &state)
{
  return state->getAny(any);
}

